package com.vne.skyemart.security;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.vne.skyemart.dao.UserDao;
import com.vne.skyemart.model.ADUser;
import com.vne.skyemart.model.Groups;
import com.vne.skyemart.model.Permission;
@Service("skyemartUserDetailsService")
@Transactional(propagation = Propagation.SUPPORTS,readOnly = true)
public class SkyemartUserDetailsService implements UserDetailsService{
	
	private Logger log = Logger.getLogger(SkyemartUserDetailsService.class);
	@Autowired
	private UserDao userDao;

	public UserDao getUserDao() {
		return userDao;
	}

	public void setUserDao(UserDao userDao) {
		this.userDao = userDao;
	}
	
	@Override
	public UserDetails loadUserByUsername(String username)
			throws UsernameNotFoundException {
		try {
			ADUser user = userDao.findUserByUsername(username, "T", "F");
			return new User(user.getUsername(), 
					user.getPassword(), 
					true, //enabled 
					true, //accountNonExpired 
					true, //credentialsNonExpired 
					true, //accountNonLocked 
					getAuthorities(user));
		} catch (Exception e) {
			log.error("can not get user ");
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}
	
	/**
	 * Retrieves a collection of {@link GrantedAuthority} based on a numerical role
	 * @param role the numerical role
	 * @return a collection of {@link GrantedAuthority
	 */
	public Collection<? extends GrantedAuthority> getAuthorities(ADUser user) {
		List<GrantedAuthority> authList = getGrantedAuthorities(getRoles(user));
		return authList;
	}
	
	/**
	 * Converts a numerical role to an equivalent list of roles
	 * @param role the numerical role
	 * @return list of roles as as a list of {@link String}
	 */
	public List<String> getRoles(ADUser user) {
		List<String> roles = new ArrayList<String>();
		
		Iterator<Groups> iGroups = user.getGroups().iterator();
		while (iGroups.hasNext()) {
			Groups groups = iGroups.next();
			Iterator<Permission> iPermission = groups.getPermissions().iterator();
			while (iPermission.hasNext()) {
				Permission permission = iPermission.next();
				roles.add(permission.getScreen().getScreenID());
			}
		}
	
		return roles;
	}
	
	/**
	 * Wraps {@link String} roles to {@link SimpleGrantedAuthority} objects
	 * @param roles {@link String} of roles
	 * @return list of granted authorities
	 */
	public static List<GrantedAuthority> getGrantedAuthorities(List<String> roles) {
		List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
		for (String role : roles) {
			authorities.add(new SimpleGrantedAuthority(role));
		}
		return authorities;
	}

}
